﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Collections.TreeCollections;
using FeatureModelCore.FMTypes;
using System.Xml.Linq;
using FeatureModelCore.FMShapes;
using FeatureModelCore.FMInterface;
using Collections;
using FeatureModelCore.FMCrossTreeConstraint;
using FeatureModelCore.FeatureModelEventArgs;

namespace FeatureModelCore
{
    public class FeatureTreeGroupRelationship : TreeNode, IRelation
    {
        private readonly static int _DEFAULT_RADIUS = 5;

        #region XML Symbol
        public readonly static string _XML_TYPE = "GroupRelationshipType";
        #endregion

        #region Properties
        public FMTreeGroupRelationshipType Type
        {
            get { return _type; }
            set
            {
                string info = string.Format("Change type to {0}"
                    , value.ToString());
                RelationModifyArgs e = new RelationModifyArgs(this
                    , info, 0, _type, value);

                this.TreeOwner.PreProcess(this, e);
                _type = value;
                this.TreeOwner.ProProcess(this, e);
            }
        }
        //public FeatureTreeRelationship[] ChildrenRelationships { get { return childrenRelationships(); } }
        public IFeature[] ChildrenNodes { get { return childrenNodes(); } }
        public IFeature ParentNode { get { return parentNode(); } }

        public FeatureTreeObjectExtension ObjectExtension { get { return _objExtension; } }

        public FMCircle Shape { get { return _circle; } set { _circle = value; } }
        #endregion

        #region Fields
        private FMTreeGroupRelationshipType _type;
        private FeatureTreeObjectExtension _objExtension;

        private FMCircle _circle;

        private bool _existError;
        private FMSet<ErrorType> _errorMessages;
        private bool _existWarning;
        private FMSet<WarningType> _warningMessages;
        #endregion

        #region Constructor
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="id"></param>
        public FeatureTreeGroupRelationship(TreeNodeIdentify id, FMTreeGroupRelationshipType type)
            : base(id)
        {
            _type = type;
            _circle = new FMCircle();
            _circle.Radius = _DEFAULT_RADIUS;
            _objExtension = new FeatureTreeObjectExtension(this);

            _existError = false;
            _existWarning = false;
            _errorMessages = new FMSet<ErrorType>();
            _warningMessages = new FMSet<WarningType>();
        }
        #endregion
        /// <summary>
        /// Construct Group Relationship
        /// </summary>
        /// <param name="id"></param>
        /// <param name="args">args[0] is FMTreeGroupRelationshipType</param>
        /// <returns></returns>
        public static FeatureTreeGroupRelationship ConstructGroupRelationship(
            TreeNodeIdentify id, object[] args)
        {
            FMTreeGroupRelationshipType type = default(FMTreeGroupRelationshipType);
            if (args != null
                && args.Length == 1
                && args[0] is FMTreeGroupRelationshipType)
            {
                type = (FMTreeGroupRelationshipType)args[0];
            }
            return new FeatureTreeGroupRelationship(id, type);
        }

        #region XML Parser
        /// <summary>
        /// To Xml
        /// </summary>
        /// <returns></returns>
        public override XElement ToXElem()
        {
            XElement xelem = base.ToXElem();
            xelem.Add(new XAttribute(_XML_TYPE, _type.ToString()));
            _circle .ToXElem(xelem);

            return xelem;
        }
        /// <summary>
        /// Xml Parser
        /// </summary>
        /// <param name="xelem"></param>
        /// <returns></returns>
        public static void xmlParser(XElement xelem, TreeObject obj)
        {
            FeatureTreeGroupRelationship newGr = obj as FeatureTreeGroupRelationship;
            if(newGr == null)
            {
                throw new Exception("Type Error!");
            }

            string typeStr = xelem.Attribute(_XML_TYPE).Value;
            FMTreeGroupRelationshipType gType = (FMTreeGroupRelationshipType)
                Enum.Parse(typeof(FMTreeGroupRelationshipType)
                , typeStr, true);

            newGr._type = gType;
            newGr._circle = FMCircle.ParseXElem(xelem);
        }
        #endregion

        #region Get Tree Hierarchy Nodes
        /// <summary>
        /// get all children relationships
        /// </summary>
        /// <returns></returns>
        //private FeatureTreeRelationship[] childrenRelationships()
        //{
        //    List<FeatureTreeRelationship> allRelationships
        //        = new List<FeatureTreeRelationship>();
        //    foreach (INonRoot chid in this.Children)
        //    {
        //        FeatureTreeRelationship r = chid as FeatureTreeRelationship;
        //        if (r != null)
        //        {
        //            allRelationships.Add(r);
        //        }
        //    }
        //    return allRelationships.ToArray<FeatureTreeRelationship>();
        //}
        /// <summary>
        /// get all children nodes
        /// </summary>
        /// <returns></returns>
        private FeatureTreeNode[] childrenNodes()
        {
            List<FeatureTreeNode> nodes = new List<FeatureTreeNode>();
            foreach (INonRoot chid in this.Children)
            {
                FeatureTreeNode node = chid as FeatureTreeNode;
                if (node != null)
                {
                    nodes.Add(node);
                }
            }
            return nodes.ToArray<FeatureTreeNode>();
        }
        /// <summary>
        /// Get parent node
        /// </summary>
        /// <returns></returns>
        private IFeature parentNode()
        {
            IFeature node = this.Parent as IFeature;
            return node;
        }
        #endregion

        public override string ToString()
        {
            return string.Format("{0},{1}"
                , base.ToString()
                , _type.ToString());
        }

        #region Warning & Error
        /// <summary>
        /// Exist Error
        /// </summary>
        public bool ExistError { get { return _existError; } }
        /// <summary>
        /// Error Messages
        /// </summary>
        public ErrorType[] ErrorMessages { get { return _errorMessages.ToArray<ErrorType>(); } }
        /// <summary>
        /// Clear
        /// </summary>
        public void ClearErrorMessages()
        {
            _existError = false;
            _errorMessages.Clear();
        }
        /// <summary>
        /// Add Error Message
        /// </summary>
        /// <param name="msg"></param>
        public void AddErrorMessage(ErrorType msg)
        {
            _existError = true;
            _errorMessages.Add(msg);
        }
        /// <summary>
        /// Exist Warning
        /// </summary>
        public bool ExistWarning { get { return _existWarning; } }
        /// <summary>
        /// Clear
        /// </summary>
        public void ClearWarningMessages()
        {
            _existWarning = false;
            _warningMessages.Clear();
        }
        /// <summary>
        /// Add Warning Message
        /// </summary>
        /// <param name="msg"></param>
        public void AddWarningMessage(WarningType msg)
        {
            _existWarning = true;
            _warningMessages.Add(msg);
        }
        /// <summary>
        /// 
        /// </summary>
        public WarningType[] WarningMessages { get { return _warningMessages.ToArray<WarningType>(); } }
        #endregion


        /// <summary>
        /// Parse 2 Tree Root
        /// </summary>
        /// <returns></returns>
        public override TreeRoot Parse2TreeRoot()
        {
            throw new Exception(String.Format("Cannnot convert {0} to TreeRoot", this.GetType().Name));
        }
        /// <summary>
        /// Clone
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            FeatureTreeGroupRelationship gR = new FeatureTreeGroupRelationship(this.ID, this._type);
            return gR;
        }
    }
}
